package com.esionet.service.impl;

import com.esionet.common.enumresource.WhetherEnum;
import com.esionet.common.exception.MyException;
import com.esionet.common.utils.FileUtil;
import com.esionet.common.utils.UploadUtil;
import com.esionet.common.utils.bean.Query;
import com.esionet.common.utils.bean.R;
import com.esionet.common.utils.bean.TreeVo;
import com.esionet.dao.SysFileDao;
import com.esionet.entity.SysFile;
import com.esionet.service.SysFileService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;


@Service("fileService")
@Transactional
@Slf4j
public class SysFileServiceImpl implements SysFileService {
    @Autowired
    private SysFileDao fileDao;
    @Autowired
    private UploadUtil uploadUtil;

    @Override
    public SysFile get(String id) {
        return fileDao.get(id);
    }

    @Override
    public List<SysFile> getList(Map<String, Object> map) {
        return fileDao.getList(map);
    }

    @Override
    public int getCount(Map<String, Object> map) {
        return fileDao.getCount(map);
    }

    @Override
    public int getCount(SysFile file) {
        return fileDao.getCount(file);
    }

    @Override
    public void save(SysFile file) {
        fileDao.save(file);
    }

    @Override
    public void update(SysFile file) {
        fileDao.update(file);
    }

    @Override
    public void delete(String id) {
        fileDao.delete(id);
    }

    @Override
    public void deleteByParams(Map<String, Object> map) {
        fileDao.deleteByParams(map);
    }

    @Override
    public void deleteBatch(String[] ids) {
        for (String id : ids) {
            SysFile file = fileDao.get(id);
            if (WhetherEnum.YES.getValue().equals(file.getIsFolder())) {
                this.deleteSonFile(file.getId());
            }
            fileDao.delete(file.getId());
        }
    }

    private void deleteSonFile(String parentId) {
        Map<String, Object> params = new HashMap<>();
        params.put("parentId", parentId);
        List<SysFile> children = fileDao.getList(params);
        for (SysFile file : children) {
            if (WhetherEnum.YES.getValue().equals(file.getIsFolder())) {
                this.restoreSonFile(file.getId());
            }
            fileDao.delete(file.getId());
        }
    }

    @Override
    public void updateStatus(String[] ids, String statusValue) {
        for (String id : ids) {
            SysFile file = new SysFile();
            file.setId(id);
            file.setIsDel(statusValue);
            fileDao.update(file);
        }
    }

    @Override
    public R addFolder(String parentId, String fileName) {
        if (StringUtils.isBlank(parentId)) {
            return R.error("请指定上级文件夹");
        }
        if (StringUtils.isBlank(fileName)) {
            return R.error("文件夹名称不能为空");
        }
        //通过文件名与上级id，判断当前文件夹 是否有同名文件夹
        Map<String, Object> params = new HashMap<>();
        params.put("parentId", parentId);
        params.put("fileName", fileName);
        int count = fileDao.getCount(params);
        StringBuilder lastName = new StringBuilder(fileName);
        //文件名已存在
        if (count > 0) {
            lastName = this.getLastName(params, fileName, WhetherEnum.YES.getValue());
        }
        SysFile file = new SysFile();
        file.setIsDel(WhetherEnum.NO.getValue());
        file.setCreateTime(new Date());
        file.setFileName(lastName.toString());
        file.setIsFolder(WhetherEnum.YES.getValue());
        file.setParentId(parentId);
        file.setFileType("folder");
        fileDao.save(file);
        return R.ok().put("lastName", lastName.toString()).put("newFolderId", file.getId());
    }

    private void addToRecycleSonSysFile(String parentId) {
        Map<String, Object> params = new HashMap<>();
        params.put("parentId", parentId);
        params.put("isDel", WhetherEnum.NO.getValue());
        List<SysFile> children = fileDao.getList(params);
        for (SysFile file : children) {
            file.setIsDel(WhetherEnum.YES.getValue());
            file.setDeleteTime(new Date());
            file.setUpdateTime(new Date());
            fileDao.update(file);
            if (WhetherEnum.YES.getValue().equals(file.getIsFolder())) {
                this.addToRecycleSonSysFile(file.getId());
            }
        }
    }

    @Override
    public void addToRecycle(String[] ids) {
        for (String id : ids) {
            SysFile file = new SysFile();
            file.setId(id);
            file.setIsDel(WhetherEnum.YES.getValue());
            file.setDeleteTime(new Date());
            file.setUpdateTime(new Date());
            fileDao.update(file);
            //下级文件
            addToRecycleSonSysFile(file.getId());
        }
    }

    @Override
    public void rename(String fileId, String newFileName) {
        SysFile file = fileDao.get(fileId);
        if (file == null) {
            throw new MyException("文件不存在");
        }
        Map<String, Object> params = new HashMap<>();
        params.put("parentId", file.getParentId());
        params.put("fileName", newFileName);
        int count = fileDao.getCount(params);
        StringBuilder lastName = new StringBuilder(newFileName);
        //文件名已存在
        if (count > 0) {
            lastName = this.getLastName(params, newFileName, file.getIsFolder());
        }
        file.setFileName(lastName.toString());
        file.setUpdateTime(new Date());
        fileDao.update(file);
    }

    @Override
    public List<TreeVo> selectFolders(String fileId) {
        List<TreeVo> treeData = new ArrayList<>();
        Map<String, Object> params = new HashMap<>();
        params.put("isDel", WhetherEnum.NO.getValue());
        params.put("isFolder", WhetherEnum.YES.getValue());
        params.put("notInclude", fileId);
        List<SysFile> folderList = fileDao.getList(params);
        for (SysFile folder : folderList) {
            if ("0".equals(folder.getParentId())) {
                TreeVo treeVo = new TreeVo(folder.getFileName(), folder.getId(), getChildren(folderList, folder.getId()));
                treeData.add(treeVo);
            }
        }

        return treeData;
    }

    @Override
    public R moveFile(String fileId, String parentId) {
        SysFile file = fileDao.get(fileId);
        if (file.getParentId().equals(parentId)) {
            return R.error("不能将文件移动到自身或其子目录下");
        }
        //通过文件名与上级id，判断当前文件夹 是否有同名文件夹
        Map<String, Object> params = new HashMap<>();
        params.put("parentId", parentId);
        params.put("isDel", WhetherEnum.NO.getValue());
        params.put("fileName", file.getFileName());
        int count = fileDao.getCount(params);
        StringBuilder lastName = new StringBuilder(file.getFileName());
        if (count > 0) {
            lastName = this.getLastName(params, file.getFileName(), file.getIsFolder());
        }
        file.setFileName(lastName.toString());
        file.setParentId(parentId);
        file.setUpdateTime(new Date());
        fileDao.update(file);
        return R.ok();
    }

    @Override
    public List<SysFile> getRecycleList(Query query) {
        return fileDao.getRecycleList(query);
    }

    @Override
    public void restoreFile(String[] ids) {
        for (String id : ids) {
            SysFile file = fileDao.get(id);
            file.setIsDel(WhetherEnum.NO.getValue());
            file.setUpdateTime(new Date());
            fileDao.update(file);
            //下级文件
            if (WhetherEnum.YES.getValue().equals(file.getIsFolder())) {
                this.restoreSonFile(file.getId());
            }
        }
    }

    private void restoreSonFile(String parentId) {
        Map<String, Object> params = new HashMap<>();
        params.put("parentId", parentId);
        params.put("isDel", WhetherEnum.YES.getValue());
        List<SysFile> children = fileDao.getList(params);
        for (SysFile file : children) {
            file.setIsDel(WhetherEnum.NO.getValue());
            file.setUpdateTime(new Date());
            fileDao.update(file);
            if (WhetherEnum.YES.getValue().equals(file.getIsFolder())) {
                this.restoreSonFile(file.getId());
            }
        }
    }

    @Override
    public void clearRecycle() {
        fileDao.clearRecycle();
    }

    private List<TreeVo> getChildren(List<SysFile> folderList, String parentId) {
        List<TreeVo> treeData = new ArrayList<>();
        for (SysFile folder : folderList) {
            if (parentId.equals(folder.getParentId())) {
                TreeVo treeVo = new TreeVo(folder.getFileName(), folder.getId(), getChildren(folderList, folder.getId()));
                treeData.add(treeVo);
            }
        }

        return treeData;
    }


    private StringBuilder getLastName(Map<String, Object> params, String fileName, String isFolder) {
        int count;
        StringBuilder lastName = new StringBuilder();
        //文件名重复自动重命名
        for (int i = 1; i >= 1; i++) {
            lastName.setLength(0);
            if (WhetherEnum.NO.getValue().equals(isFolder)) {
                String name = fileName.substring(0, fileName.lastIndexOf("."));
                String suffix = fileName.substring(fileName.lastIndexOf("."), fileName.length());
                lastName = lastName.append(name).append("(").append(i).append(")").append(suffix);
            } else {
                lastName = lastName.append(fileName).append("(").append(i).append(")");
            }
            params.put("fileName", lastName.toString());
            count = fileDao.getCount(params);
            //当前文件名可用
            if (count == 0) {
                break;
            }
        }
        return lastName;
    }


    @Override
    public R upload(MultipartFile multipartFile, String parentId) {

        Map<String, Object> res = new HashMap<>();
        try {
            if (multipartFile.isEmpty()) {
                return R.error("上传文件不能为空");
            }
            String fileName = multipartFile.getOriginalFilename();
            if (StringUtils.isEmpty(fileName)) {
                return R.error("文件名不能为空");
            }
            if (StringUtils.isBlank(parentId)) {
                return R.error("请指定上级文件夹");
            }
            //上传至七牛云
            String fileUrl= uploadUtil.uploadFile(multipartFile);
            //获取文件类型
            String fileType = FileUtil.getFileType(fileName);
            //通过文件名与上级id，判断当前文件夹 是否有同名文件夹
            Map<String, Object> params = new HashMap<>();
            params.put("parentId", parentId);
            params.put("fileName", fileName);
            int count = fileDao.getCount(params);
            StringBuilder lastName = new StringBuilder(fileName);
            //文件名已存在
            if (count > 0) {
                lastName = this.getLastName(params, fileName, WhetherEnum.NO.getValue());
            }
            SysFile file = new SysFile();
            file.setFileName(lastName.toString());
            file.setMd5(UUID.randomUUID().toString());
            file.setFileUrl(fileUrl);

            file.setParentId(parentId);
            file.setIsFolder(WhetherEnum.NO.getValue());
            file.setFileType(fileType);
            file.setFileSize(multipartFile.getSize());
            file.setFileSuffix(FileUtil.getFileSuffix(fileName));
            file.setIsDel(WhetherEnum.NO.getValue());
            file.setCreateTime(new Date());
            fileDao.save(file);

            res.put("fileUrl", fileUrl);
            res.put("fileName", lastName);
            R.ok().put("data", res);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("上传失败:" + multipartFile.getOriginalFilename());
            return  R.error("上传失败");

        }
        return R.ok().put("data", res);
    }

    @Override
    public List<SysFile> getImgList(Query query) {
        return fileDao.getImgList(query);
    }
}
